梦想不会自己发光,真正闪耀的是那个为梦狂奔的你。献给知行的孩子们!(Eric.He著)
对多个任务 / 作业 / 活动进行调度,目标是最小化总完成时间、等待时间、延迟时间或最大化任务完成数,每一步选择对当前调度目标最优的任务。
本教程以多个任务调度贪心算法案例场景为例,让大家彻底理解以 “局部最优” 推导 “全局最优” 的核心逻辑,并掌握单机任务调度、多机任务调度的原理及代码实现。
问题描述:
算法解析:
#include <iostream>
#include <vector>
using namespace std;
// 活动结构体:开始时间、结束时间、演讲编号
struct Activity {
int start;
int end;
int id;
};
// 按结束时间升序排序
bool compareActivity(const Activity& a, const Activity& b) {
return a.end < b.end;
}
// 活动选择:返回选中的活动编号
vector<int> activitySelection(vector<Activity>& activities) {
sort(activities.begin(), activities.end(), compareActivity);
vector<int> selected;
// 第一个活动必选
selected.push_back(activities[0].id);
int lastEnd = activities[0].end;
for (int i = 1; i < activities.size(); ++i) {
// 当前活动开始时间 >= 上一个活动结束时间,无冲突
if (activities[i].start >= lastEnd) {
selected.push_back(activities[i].id);
lastEnd = activities[i].end;
}
}
return selected;
}
int main() {
// 测试:6个活动,格式(start, end, id)
vector<Activity> acts = {{1,4,1}, {3,5,2}, {0,6,3}, {5,7,4}, {3,8,5}, {7,9,6}};
vector<int> res = activitySelection(acts);
cout << "选中的活动编号:";
for (int id : res) cout << id << " ";
return 0;
}
输出:1 4 6
问题描述:
算法解析:
核心思路是短任务优先分配,结合水龙头的空闲状态动态调度,最终实现总耗时最优。
举例验证:
场景:n=5 人,打水时间[5,3,1,4,2],r=2 个水龙头。
若反序分配(长时间优先):排序[5,4,3,2,1],总耗时之和 = 5+4+8+6+9=32,远大于最优解。
#include <iostream>
#include <vector>
using namespace std;
// 计算打水最小总耗时(总耗时=所有人的打水+等待时间之和)
// 参数:t - 原始打水时间数组,r - 水龙头数量
long long minTotalWaterTime(vector<int>& t, int r) {
int n = t.size();
// 边界情况:无人员或无水龙头
if (n == 0) return 0;
if (r <= 0) return LLONG_MAX;
// 步骤1:将打水时间升序排序(短任务优先)
sort(t.begin(), t.end());
// 步骤2:初始化
vector<long long> tap_times(r, 0);// 记录任务时间
vector<vector<int>> tap_tasks(r);// 记录水龙头分配的任务
vector<vector<int>> tap_wait(r);// 记录等待时间
long long total_time = 0; //记录总耗时
// 步骤3:遍历排序后的打水时间,依次分配给最早空闲的水龙头
for (int time : t) {
// 找到当前累积耗时最小的水龙头索引
int min_idx = 0;
for (int i = 1; i < r; ++i) {
if (tap_times[i] < tap_times[min_idx]) {
min_idx = i;
}
}
// 分配任务,更新水龙头累积耗时
tap_times[min_idx] += time;
tap_tasks[min_idx].push_back(time);
}
// 打印调度结果
cout << "==================== 水龙头调度分配结果 ====================" << endl;
for (int i = 0; i < r; ++i) {
cout << "水龙头" << i+1 << ":分配任务[";
int tasks_time = 0;// 记录任务耗时
for (int j = 0; j < tap_tasks[i].size(); ++j) {
if (j > 0) cout << ", ";
cout << tap_tasks[i][j];
tasks_time += tap_tasks[i][j];
}
cout << "] | 任务耗时:" << tasks_time << "ms" << endl;
}
cout << "============================================================" << endl;
// 步骤4:计算任务等待时间
for (int i = 0; i < r; ++i) {
tap_wait[i].push_back(0);//每个水龙头的第一个任务微等待时间为0
for(int j = 1; j < tap_tasks[i].size(); ++j)
{
tap_wait[i].push_back(tap_tasks[i][j-1] + tap_wait[i][j-1]);//当前任务等待时间 = 上一个任务等待时间 + 上一个任务时间
}
}
// 打印任务等待耗时结果
cout << "==================== 任务等待耗时结果 ====================" << endl;
for (int i = 0; i < r; ++i) {
cout << "水龙头" << i+1 << ":任务等待[";
int total_wait = 0;
for (int j = 0; j < tap_tasks[i].size(); ++j) {
if (j > 0) cout << ", ";
cout << tap_wait[i][j] ;
total_wait += tap_wait[i][j] ;
}
cout << "] | 等待耗时:" << total_wait << "ms" << endl;
}
cout << "============================================================" << endl;
// // 步骤5:计算任务总耗时
cout << "==================== 任务总耗时结果 ====================" << endl;
for (int i = 0; i < r; ++i) {
long long sum_time = 0;
cout << "水龙头" << i+1 << ":任务总耗时[";
for (int j = 0; j < tap_tasks[i].size(); ++j) {
if (j > 0) cout << ", ";
sum_time = sum_time + tap_tasks[i][j] + tap_wait[i][j];
cout << tap_tasks[i][j] << "+" << tap_wait[i][j] << "=" << tap_tasks[i][j] + tap_wait[i][j];
}
total_time += sum_time; // 步骤4:计算总耗时(所有水龙头累积耗时之和)
cout << "] | 总耗时:" << sum_time << "ms" << endl;
}
cout << "============================================================" << endl;
return total_time;
}
int main() {
// 输入:人数n、水龙头数r
int n, r;
cout << "请输入打水人数n:";
cin >> n;
cout << "请输入水龙头数量r:";
cin >> r;
// 输入:n个人的打水时间(互不相等的正整数)
vector<int> t(n);
cout << "请输入" << n << "个人的打水时间(空格分隔,互不相等正整数):";
for (int i = 0; i < n; ++i) {
cin >> t[i];
}
// 计算最小总耗时
long long min_total = minTotalWaterTime(t, r);
// 输出结果
cout << "所有人打水的最小总花费时间(打水+等待):" << min_total << "ms" << endl;
return 0;
}
请输入打水人数n:5
请输入水龙头数量r:2
请输入5个人的打水时间(空格分隔,互不相等正整数):1 2 3 4 5
==================== 水龙头调度分配结果 ====================
水龙头1:分配任务[1, 3, 5] | 任务耗时:9ms
水龙头2:分配任务[2, 4] | 任务耗时:6ms
============================================================
==================== 任务等待耗时结果 ====================
水龙头1:任务等待[0, 1, 4] | 等待耗时:5ms
水龙头2:任务等待[0, 2] | 等待耗时:2ms
============================================================
==================== 任务总耗时结果 ====================
水龙头1:任务总耗时[1+0=1, 3+1=4, 5+4=9] | 总耗时:14ms
水龙头2:任务总耗时[2+0=2, 4+2=6] | 总耗时:8ms
============================================================
所有人打水的最小总花费时间(打水+等待):22ms